#include <ani.h>
#include <array>
#include <iostream>
#include <vector>

ani_ref createDouble(ani_env *env, ani_double value){
    ani_class cls;
    env->FindClass("std.core.Double",&cls);
    ani_method ctor;
    env->Class_FindMethod(cls, "<ctor>", "d:", &ctor);

    ani_object rs;
    env->Object_New(cls, ctor, &rs, value);
    return static_cast<ani_object>(rs);
}

ani_int IsFunctionObject(ani_env* env, ani_object obj) {
    ani_class funcClass;
    // 仅有InstanceOf可以使用该签名，不带数字的Function
    env->FindClass("std.core.Function2", &funcClass);
    
    ani_boolean result;
    env->Object_InstanceOf(obj, funcClass, &result);
    return result;
}

// 使用Class_BindNativeMethods绑定时需要添加[[maybe_unused]] ani_object obj作为class的this指针。Namespace_BindNativeMethods时不需要。
static ani_double handleData(ani_env *env, ani_fn_object fnObj, ani_double val_double1, ani_double val_double2)
{

    // 构造入参数组
    std::vector<ani_ref> vec;
    // 基本类型转换为ani_ref需要装箱。
    auto val1 = createDouble(env, val_double1);
    auto val2 = createDouble(env, val_double2);
    vec.push_back(val1);
    vec.push_back(val2);

    ani_ref fnReturnVal;
    env->FunctionalObject_Call(fnObj, vec.size(), vec.data(), &fnReturnVal);

    // 返回值类型如果要求是基本类型如ani_int、ani_double需要解包。
    ani_double sumRs;
    env->Object_CallMethodByName_Double(static_cast<ani_object>(fnReturnVal), "toDouble", ":d", &sumRs);

    return sumRs;
}

ani_double CallFn(ani_env *env, ani_double val_double1, ani_double val_double2)
{
    ani_object classObj = {};
    static const char *className = "ani_fn_object.OptionalClass";
    ani_class cls;
    if (ANI_OK != env->FindClass(className, &cls)) {
        std::cerr << "Not found '" << className << "'" << std::endl;
    }

    ani_method ctor;
    if (ANI_OK != env->Class_FindMethod(cls, "<ctor>", nullptr, &ctor)){
        std::cerr << "get ctor Failed'" << className << "'" << std::endl;
    }

    //创建一个实例
    if (ANI_OK != env->Object_New(cls, ctor, &classObj)){
        std::cerr << "Create Object Failed'" << className << "'" << std::endl;
    }

    ani_ref fn_ref;
    env->Object_GetFieldByName_Ref(classObj, "fn", &fn_ref);

    // 构造入参数组
    std::vector<ani_ref> vec;
    // 基本类型转换为ani_ref需要装箱。
    auto val1 = createDouble(env, val_double1);
    auto val2 = createDouble(env, val_double2);
    vec.push_back(val1);
    vec.push_back(val2);

    ani_ref fnReturnVal;
    env->FunctionalObject_Call(static_cast<ani_fn_object>(fn_ref), vec.size(), vec.data(), &fnReturnVal);

    // 返回值类型如果要求是基本类型如ani_int、ani_double需要解包。
    ani_double sumRs;
    env->Object_CallMethodByName_Double(static_cast<ani_object>(fnReturnVal), "toDouble", ":d", &sumRs);

    return sumRs;
}


ani_status ANI_Constructor(ani_vm *vm, uint32_t *result)
{
    ani_env *env;

    if (ANI_OK != vm->GetEnv(ANI_VERSION_1, &env))
    {
        std::cerr << "Unsupported ANI_VERSION_1" << std::endl;
        return ANI_ERROR;
    }

    static const char *moduleName = "ani_fn_object";

    ani_module module;
    if (ANI_OK != env->FindModule(moduleName, &module))
    {
        std::cerr << "Not found '" << moduleName << "'" << std::endl;
        return ANI_ERROR;
    }

    std::array methods = {
        // Function<number> 其中<number>是0-N的整数，表示函数的参数数量。
        ani_native_function{"handleData", "C{std.core.Function2}dd:d", reinterpret_cast<void *>(handleData)},
        ani_native_function{"CallFn", "dd:d", reinterpret_cast<void *>(CallFn)},
    };

    std::cout << "Start bind native methods to '" << moduleName << "'" << std::endl;

    if (ANI_OK != env->Module_BindNativeFunctions(module, methods.data(), methods.size()))
    {
        std::cerr << "Cannot bind native methods to '" << moduleName << "'" << std::endl;
        return ANI_ERROR;
    };
    std::cout << "Finish bind native methods to '" << moduleName << "'" << std::endl;

    *result = ANI_VERSION_1;
    return ANI_OK;
}

/**
3
 */